﻿using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.ExceptionServices;
using System.Runtime.InteropServices;
using System.Security;

namespace Hsenl {
    // 当函数是 async HTask 时, 由该Builder来创建并操作task
    [StructLayout(LayoutKind.Auto)]
    public struct AsyncHTaskMethodBuilder {
        private HTask _task;

        [DebuggerHidden]
        private AsyncHTaskMethodBuilder(HTask task) {
            this._task = task;
        }

        // 1. Static Create method.
        [DebuggerHidden]
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static AsyncHTaskMethodBuilder Create() => new(new HTask(null, HTaskType.Builder));

        // 2. TaskLike Task property(void)
        [DebuggerHidden]
        public HTask Task {
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            // 例如, private async HTask Func(){ ... }, Func返回的task, 就是这里提供的, 如果 task 为空, 则代表在 Func() 内部, 从来没有真正的异步挂起过, 比如 await HTask.Completed;
            get => this._task;
        }

        // 3. SetException
        [DebuggerHidden]
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void SetException(Exception e) {
            if (!this._task.IsNull) {
                this._task.SetException_Internal(e);
                return;
            }

            if (e is OperationCanceledException)
                return;

            // 没有 body, 所以, 我们这里直接把异常抛出
            ExceptionDispatchInfo.Capture(e).Throw();
        }

        // 4. SetResult
        [DebuggerHidden]
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void SetResult() {
            this._task.SetResult_Internal();
        }

        // 5. AwaitOnCompleted
        [DebuggerHidden]
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
            where TAwaiter : INotifyCompletion where TStateMachine : IAsyncStateMachine {
            // 该方法被调用时, 说明状态机被挂起了, 所以要创建一个task, 用于保存continuation, 不然回调链会断掉
            if (this._task.IsNull) {
                this._task = HTask.Builder();
            }

            var body = this._task.Body;
            body.StateMachine = stateMachine;
            // 把自己的MoveNext交给下层的awaiter, 当下层的task进行SetResult时, 可以通过这个回调让自己继续执行MoveNext, 并通过下层的await.GetResult来获取其返回的值
            awaiter.OnCompleted(body.MoveNext);
        }

        // 6. AwaitUnsafeOnCompleted
        [DebuggerHidden]
        [SecuritySafeCritical]
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
            where TAwaiter : ICriticalNotifyCompletion where TStateMachine : IAsyncStateMachine {
            if (this._task.IsNull) {
                this._task = HTask.Builder();
            }

            var body = this._task.Body;
            body.StateMachine = stateMachine;
            awaiter.UnsafeOnCompleted(body.MoveNext);
        }

        // 7. Start
        [DebuggerHidden]
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine {
            stateMachine.MoveNext();
        }

        // 8. SetStateMachine
        [DebuggerHidden]
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void SetStateMachine(IAsyncStateMachine stateMachine) { }
    }


    [StructLayout(LayoutKind.Auto)]
    public struct AsyncHTaskMethodBuilder<T> {
        private HTask<T> _task;

        [DebuggerHidden]
        private AsyncHTaskMethodBuilder(HTask<T> task) {
            this._task = task;
        }

        // 1. Static Create method.
        [DebuggerHidden]
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static AsyncHTaskMethodBuilder<T> Create() => new(new HTask<T>(null, HTaskType.Builder));

        // 2. TaskLike Task property(void)
        [DebuggerHidden]
        public HTask<T> Task {
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            get => this._task;
        }

        // 3. SetException
        [DebuggerHidden]
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void SetException(Exception e) {
            if (!this._task.IsNull) {
                this._task.SetException_Internal(e);
                return;
            }

            if (e is OperationCanceledException)
                return;

            ExceptionDispatchInfo.Capture(e).Throw();
        }

        // 4. SetResult
        [DebuggerHidden]
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void SetResult(T value) {
            this._task.SetResult_Internal(value);
        }

        // 5. AwaitOnCompleted
        [DebuggerHidden]
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
            where TAwaiter : INotifyCompletion where TStateMachine : IAsyncStateMachine {
            if (this._task.IsNull) {
                this._task = HTask<T>.Builder();
            }

            var body = this._task.Body;
            body.StateMachine = stateMachine;
            awaiter.OnCompleted(body.MoveNext);
        }

        // 6. AwaitUnsafeOnCompleted
        [DebuggerHidden]
        [SecuritySafeCritical]
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
            where TAwaiter : ICriticalNotifyCompletion where TStateMachine : IAsyncStateMachine {
            if (this._task.IsNull) {
                this._task = HTask<T>.Builder();
            }

            var body = this._task.Body;
            body.StateMachine = stateMachine;
            awaiter.UnsafeOnCompleted(body.MoveNext);
        }

        // 7. Start
        [DebuggerHidden]
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine {
            stateMachine.MoveNext();
        }

        // 8. SetStateMachine
        [DebuggerHidden]
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void SetStateMachine(IAsyncStateMachine stateMachine) { }
    }
}